package com.func.domain.strategy.repository;

import com.func.domain.strategy.model.entity.StrategyAwardEntity;
import com.func.domain.strategy.model.entity.StrategyEntity;
import com.func.domain.strategy.model.entity.StrategyRuleEntity;
import com.func.domain.strategy.model.valobj.RuleTreeVO;
import com.func.domain.strategy.model.valobj.RuleWeightVO;
import com.func.domain.strategy.model.valobj.StrategyAwardRuleModelVo;
import com.func.domain.strategy.model.valobj.StrategyAwardStockKeyVO;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @ClassName IStrategyRepository
 * @Description 策略仓储接口
 * @Author: func
 * @Date 2025/2/19 1:20
 * @Version 1.0
 */

public interface IStrategyRepository {
    /**
     * 通过策略Id, 从数据库中查到对应的策略奖品的实体列表
     * @param strategyId 策略Id
     * @return 策略奖品实体列表
     */
    List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId);

    /**
     * 存储概率查找表, 也就是格子数组存储到Redis中, 还有概率范围(格子数组的长度)也存储到Redis中
     * @param key 会和Constants中的两个常量组合成两个key用作Redis存储的key
     * @param rateRange 概率范围 = totalRate / minRate
     * @param shuffleStrategyAwardSearchRateTables 乱序后的概率查找表
     */
    void storeStrategyAwardRateTables(String key, Integer rateRange, Map<Integer, Integer> shuffleStrategyAwardSearchRateTables);

    /**
     * 重载支持通过Long类型的策略Id查询到对应的概率范围
     * @param strategyId 策略Id
     * @return 概率范围
     */
    int getRateRange(Long strategyId);

    /**
     * 从Redis中根据这个key拼接成的key查找对应的概率范围
     * @param key key
     * @return 概率范围
     */
    int getRateRange(String key);

    /**
     * 执行一次抽奖, 通过rateKey从Redis的map中查询到这个index对应的格子中存储的是什么奖品
     * @param key 关键键值
     * @param rateKey 格子数组的索引, 并不是概率的意思, 关键是后面的key
     * @return 抽到的奖品Id
     */
    Integer getStrategyAwardAssemble(String key, int rateKey);

    /**
     * 通过策略的ID查找到对应的策略实体, 优先走缓存, 其次走数据库查询
     * @param strategyId 策略Id
     * @return 查询到的策略实体
     */
    StrategyEntity queryStrategyEntityByStrategyId(Long strategyId);

    /**
     * 通过策略Id和ruleModel从Strategy_rule表中查询到唯一的策略实体, 这里还是保证不了唯一性的, 但是只是用来查询rule_weight还是可以的
     * @param strategyId 策略Id
     * @param ruleModel 策略模式
     * @return
     */
    StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel);

    /**
     * 获取策略规则表中的rule_value
     * @param strategyId 策略ID
     * @param awardId 奖品ID
     * @param ruleModel 规则模型
     * @return rule_value
     */
    String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel);
    String queryStrategyRuleValue(Long strategyId, String ruleModel);

    /**
     * 算是重载queryStrategyRuleValue方法, 因为RuleWeightKey就是rule_weight的ruleValue
     * @param strategyId
     * @param ruleModel
     * @param awardId
     * @return
     */
    String queryStrategyRuleWeightKey(Long strategyId, String ruleModel, Integer awardId);

    /**
     * 从strategy_award中查找rule_models并存到抽奖策略规则规则值对象
     * @param strategyId
     * @param awardId
     * @return 抽奖策略规则规则值对象
     */
    StrategyAwardRuleModelVo queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId);

    /**
     * 根据treeId从数据库中获取数据并构建一颗规则树
     * @param treeId 规则树ID
     * @return 已经构建好的规则树
     */
    RuleTreeVO queryRuleTreeVO(String treeId);

    /**
     * 在数据中更新奖品库存-1
     * @param strategyId
     * @param awardId
     */
    void updateStrategyAwardStock(Long strategyId, Integer awardId);

    /**
     * 从延迟队列中获取到需要更新的奖品
     * @return 奖品库存Key信息
     * @throws InterruptedException 异常
     */
    StrategyAwardStockKeyVO takeQueueValue() throws InterruptedException;

    void awardStockConsumeSendQueue(StrategyAwardStockKeyVO strategyAwardStockKeyVO);

    Boolean subtractionAwardStock(String cacheKey, Date endDateTime);

    /**
     * 在Redis中装配这个奖品的库存
     * @param key
     * @param awardCount
     */
    void cacheStrategyAwardCount(String key, Integer awardCount);

    /**
     * 查询策略奖品
     * @param strategyId
     * @param awardId
     * @return
     */
    StrategyAwardEntity queryStrategyAward(Long strategyId, Integer awardId);

    Long queryStrategyIdByActivityId(Long activityId);

    List<StrategyAwardEntity> queryStrategyAwardListByActivityId(Long activityId);

    Map<String, Integer> queryAwardRuleLockCount(String[] treeIds);

    Integer queryTodayUserRaffleCount(String userId, Long strategyId);

    List<RuleWeightVO> queryAwardRuleWeight(Long strategyId);

    Integer queryActivityAccountTotalUserCount(String userId, Long strategyId);
}
